/*********************************************************************
* File: util.cpp
*
* \brief Miscellaneous utility functions.
*
* \author Instituto Superior Tecnico de Lisboa, Portugal
* \author Technical University of Lisbon, Portugal
* 
* \author Agentes Autonomos e Sistemas Multiagente
* \author Autonomous Agents and Multiagent Systems
* 
* \version	1.0
* \date		2006/2007
*********************************************************************/
#include "util.h"
#include <assert.h>
#include <float.h>
#include "mathLibrary.h"
#include "../modApi.h"
#include "../game/waypoint.h"
#include "../agents/Agent.h"
using namespace agents;
using namespace util;

int gmsgTextMsg = 0;
int gmsgShowMenu = 0;
int gmsgShake = 0;
int gmsgStatusText = 0;
char *g_tag1[NUM_TAGS] = {
"-=","-[","-]","-}","-{","<[","<]","[-","]-","{-","}-","[[","[","{","]","}","<",">","-","|","=","+"};
char *g_tag2[NUM_TAGS] = {
"=-","]-","[-","{-","}-","]>","[>","-]","-[","-}","-{","]]","]","}","[","{",">","<","-","|","=","+"};

bool util::g_isFakeClientCommand = false; // Faked Client Command
int util::g_fakeArgCount;
char util::g_argv[256];
char arg[256];

extern short g_sModelIndexLaser;
extern short g_sModelIndexArrow;

/**
* \brief Used for use tracing and shot targeting. 
* 
* Traces are blocked by bbox and exact bsp entities.
**/
void util::traceline( 
				   const Vector &vecStart, const Vector &vecEnd, 
				   IGNORE_MONSTERS igmon, IGNORE_GLASS ignoreGlass, 
				   edict_t *pentIgnore, TraceResult *ptr ) {
   TRACE_LINE( vecStart, vecEnd, (igmon == ignore_monsters ? 1 : 0) | (ignoreGlass ? 0x100 : 0), pentIgnore, ptr ); }

				   /**
* \brief Used for use tracing and shot targeting.
* 
* Traces are blocked by bbox and exact bsp entities.
**/
void util::traceline( 
				   const Vector &vecStart, const Vector &vecEnd, 
				   IGNORE_MONSTERS igmon, edict_t *pentIgnore, 
				   TraceResult *ptr ) {
   TRACE_LINE( vecStart, vecEnd, (igmon == ignore_monsters ? true : false), pentIgnore, ptr ); }
/**
*
**/
void util::traceHull( 
				   const Vector &vecStart, const Vector &vecEnd, 
				   IGNORE_MONSTERS igmon, int hullNumber, edict_t *pentIgnore, 
				   TraceResult *ptr ) {
   TRACE_HULL( vecStart, vecEnd, (igmon == ignore_monsters ? true : false), hullNumber, pentIgnore, ptr ); }
/**
*
**/
void util::traceModel( 
					const Vector &vecStart, const Vector &vecEnd, 
					int hullNumber, edict_t *pentModel, TraceResult *ptr ) {
   g_engfuncs.pfnTraceModel( vecStart, vecEnd, hullNumber, pentModel, ptr );
}


/**
*
**/
void util::decalTrace( TraceResult *pTrace, char* pszDecalName )
{
   short entityIndex;
   int index;
   int message;

   index = DECAL_INDEX(pszDecalName);
   if (index < 0)
      index = 0;

   if (pTrace->flFraction == 1.0)
      return;

   // Only decal BSP models
   if ( !FNullEnt(pTrace->pHit) )
   {
      edict_t *pHit = pTrace->pHit;

      if (pHit->v.solid == SOLID_BSP || pHit->v.movetype == MOVETYPE_PUSHSTEP)
         entityIndex = ENTINDEX(pHit);
      else
         return;
   }
   else 
      entityIndex = 0;

   message = TE_DECAL;
   if ( entityIndex != 0 )
   {
      if ( index > 255 )
      {
         message = TE_DECALHIGH;
         index -= 256;
      }
   }
   else
   {
      message = TE_WORLDDECAL;
      if ( index > 255 )
      {
         message = TE_WORLDDECALHIGH;
         index -= 256;
      }
   }

   MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY );
      WRITE_BYTE( message );
      WRITE_COORD( pTrace->vecEndPos.x );
      WRITE_COORD( pTrace->vecEndPos.y );
      WRITE_COORD( pTrace->vecEndPos.z );
      WRITE_BYTE( index );
      if ( entityIndex )
         WRITE_SHORT( entityIndex );
   MESSAGE_END();
}



/**
*
**/
void util::drawBeam(edict_t *pEntity, Vector start, Vector end, int width,
        int noise, int red, int green, int blue, int brightness, int speed, int life)
{
   if (!util::isPlayer(pEntity))
      return; // reliability check

   MESSAGE_BEGIN(MSG_ONE_UNRELIABLE, SVC_TEMPENTITY, NULL, pEntity);
   WRITE_BYTE(TE_BEAMPOINTS);
   WRITE_COORD(start.x);
   WRITE_COORD(start.y);
   WRITE_COORD(start.z);
   WRITE_COORD(end.x);
   WRITE_COORD(end.y);
   WRITE_COORD(end.z);
   WRITE_SHORT(g_sModelIndexLaser);
   WRITE_BYTE(0); // framestart
   WRITE_BYTE(10); // framerate
   WRITE_BYTE(life); // life in 0.1's
   WRITE_BYTE(width); // width
   WRITE_BYTE(noise);  // noise

   WRITE_BYTE(red);   // r, g, b
   WRITE_BYTE(green);   // r, g, b
   WRITE_BYTE(blue);   // r, g, b

   WRITE_BYTE(brightness);   // brightness
   WRITE_BYTE(speed);    // speed
   MESSAGE_END();
}

/**
*
**/
void util::drawArrow(edict_t *pEntity, Vector start, Vector end, int width,
        int noise, int red, int green, int blue, int brightness, int speed, int life)
{
   if (!util::isPlayer(pEntity))
      return; // reliability check

   MESSAGE_BEGIN(MSG_ONE_UNRELIABLE, SVC_TEMPENTITY, NULL, pEntity);
   WRITE_BYTE(TE_BEAMPOINTS);
   WRITE_COORD(end.x);
   WRITE_COORD(end.y);
   WRITE_COORD(end.z);
   WRITE_COORD(start.x);
   WRITE_COORD(start.y);
   WRITE_COORD(start.z);
   WRITE_SHORT(g_sModelIndexArrow);
   WRITE_BYTE(0); // framestart
   WRITE_BYTE(10); // framerate
   WRITE_BYTE(life); // life in 0.1's
   WRITE_BYTE(width); // width
   WRITE_BYTE(noise);  // noise

   WRITE_BYTE(red);   // r, g, b
   WRITE_BYTE(green);   // r, g, b
   WRITE_BYTE(blue);   // r, g, b

   WRITE_BYTE(brightness);   // brightness
   WRITE_BYTE(speed);    // speed
   MESSAGE_END();
}

/**
* \brief A more accurate (and slower) version of #util::fVisible. 
**/
bool util::fBoxVisible(edict_t *pEdict, edict_t *pTargetEdict, Vector *pvHit, unsigned char *ucBodyPart)
{
   *ucBodyPart = 0;
   entvars_t *pevLooker = VARS(pEdict);
   entvars_t *pevTarget = VARS(pTargetEdict);

   // don't look through water
   if ((pevLooker->waterlevel != 3 && pevTarget->waterlevel == 3) 
      || (pevLooker->waterlevel == 3 && pevTarget->waterlevel == 0))
      return false;

   TraceResult tr;
   Vector vecLookerOrigin = pevLooker->origin + pevLooker->view_ofs;
   Vector vecTarget = pevTarget->origin;

   // Check direct Line to waist
   util::traceline(vecLookerOrigin, vecTarget, ignore_monsters, ignore_glass, pEdict, &tr);

   if (tr.flFraction == 1.0)
   {
      *pvHit = tr.vecEndPos;
      *ucBodyPart |= VisibleBodyParts::waist;
   }

   vecTarget = vecTarget + pevTarget->view_ofs; // Check direct Line to head
   util::traceline(vecLookerOrigin, vecTarget, ignore_monsters, ignore_glass, pEdict, &tr);

   if (tr.flFraction == 1.0)
   {
      *pvHit = tr.vecEndPos;
      *ucBodyPart |= VisibleBodyParts::head; 
   }

   if (*ucBodyPart != 0)
      return true;

   for (int i = 0; i < 5; i++) // Nothing visible - check randomly other Parts of Body
   {
      Vector vecTarget = pevTarget->origin;
      vecTarget.x += RANDOM_FLOAT(pevTarget->mins.x, pevTarget->maxs.x);
      vecTarget.y += RANDOM_FLOAT(pevTarget->mins.y, pevTarget->maxs.y);
      vecTarget.z += RANDOM_FLOAT(pevTarget->mins.z, pevTarget->maxs.z);

      util::traceline(vecLookerOrigin, vecTarget, ignore_monsters, ignore_glass, pEdict, &tr);

      if (tr.flFraction == 1.0)
      {
         // Return seen position
         *pvHit = tr.vecEndPos;
         *ucBodyPart |= VisibleBodyParts::custom;
         return true;
      }
   }

   return false;
}


/**
* \brief Whether a point is visible by an agent.
*
* \param[in] target The point whose is visibility is to be analysed.
* \param[in] pEdict The agent.
**/
bool util::fVisible(const Vector &target, edict_t *pEdict )
{
   TraceResult tr;
   Vector vecLookerOrigin;

   vecLookerOrigin = pEdict->v.origin + pEdict->v.view_ofs; // look through caller's eyes

   bool bInWater = (POINT_CONTENTS(target) == CONTENTS_WATER);
   bool bLookerInWater = (POINT_CONTENTS(vecLookerOrigin) == CONTENTS_WATER);

   if (bInWater != bLookerInWater) // don't look through water
      return false;

   util::traceline(vecLookerOrigin, target, ignore_monsters, ignore_glass, pEdict, &tr);

   if (tr.flFraction != 1.0)
      return false;  // Line of sight is not established
   else
      return true;  // line of sight is valid.
}

bool util::fVisibleViewCone(Vector &target, edict_t *pEdict )
{
	if(util::fInViewCone(&target, pEdict))
	{
		return util::fVisible(target,pEdict);
	}
	return false;
}

/**
*
**/
bool util::fInViewCone(Vector *pOrigin, edict_t *pEdict)
{
   return util::getShootingConeDeviation(pEdict, pOrigin) >=
      cos((pEdict->v.fov / 2) * M_PI / 180);
}

/**
*
**/
float util::getShootingConeDeviation(edict_t *pEdict, Vector *pvecPosition)
{
   Vector vecDir = (*pvecPosition - (pEdict->v.origin + pEdict->v.view_ofs)).Normalize();
   util::math::makeVectors(pEdict->v.v_angle);
   return (DotProduct(gpGlobals->v_forward, vecDir));
}

/**
*
**/
Vector util::vecBModelOrigin(edict_t *pEdict)
{
   return pEdict->v.absmin + (pEdict->v.size * 0.5);
}


/**
* \brief Gets the vector position of the Bone bone in the Entity entity.
*
* \param[in] entity Entity which bone belongs to.
* \param[in] bone Bone Index in model.
* \param[in] targetPoint Parameter that gives the vector where bone is.
**/
void util::getBonePosition(edict_t* entity, int bone, Vector* position)
{
	Vector angles;

	GET_BONE_POSITION(entity, bone, *position, angles);
}
/**
* \brief Whether the agent is alive.
**/
bool util::isAlive(edict_t *pEdict)
{
   if (FNullEnt(pEdict))
      return false; // reliability check

   return (pEdict->v.deadflag == DEAD_NO &&
      pEdict->v.health > 0/* &&
      pEdict->v.movetype != MOVETYPE_NOCLIP*/);
}


/**
*
**/
bool util::isPlayer(edict_t *pEdict) {
   if (FNullEnt(pEdict))
      return false;
   else if (pEdict->free)
      return false;
   else if (pEdict->v.flags & (FL_CLIENT | FL_FAKECLIENT))
      return (STRING(pEdict->v.netname)[0] != 0);
   return false;
}
/**
*
**/
bool util::isHumanPlayer(edict_t *pEdict) {
   if (FNullEnt(pEdict))
      return false;
   else if (pEdict->free)
      return false;
   else if (pEdict->v.flags & FL_CLIENT)
      return (STRING(pEdict->v.netname)[0] != 0);
   return false;
}


/**
* \brief Get the index of the nearest player to a certain point.
*
* \param[in] position A point in three dimensional space.
**/
int util::getNearestPlayerIndex(Vector position)
{
   float fDistance2;
   float fMinDistance2 = FLT_MAX;
   int index = 0;

   for (int i = 0; i < gpGlobals->maxClients; i++)
   {
      if (g_threatTab[i].isAlive == false || g_threatTab[i].isUsed == false)
         continue;

      fDistance2 = util::math::lengthSquared(g_threatTab[i].pEdict->v.origin - position);

      if (fDistance2 < fMinDistance2)
      {
         index = i;
         fMinDistance2 = fDistance2;
      }
   }

   return index;
}

/**
* \brief Get the agent with the highest frags from a certain team.
*
* \param[in] team The team.
**/
int util::getHighestFragsBot(int team)
{
   Agent *pFragBot;
   int iBestIndex = 0;
   float fBestFrags = -1;

   // Search Bots in this team
   for (int bot_index = 0; bot_index < gpGlobals->maxClients; bot_index++)
   {
      pFragBot = g_world->agents[bot_index];
      if (pFragBot)  
      {
         if (util::isAlive(pFragBot->getEdict()) && util::getTeam(pFragBot->getEdict()) == team)
         {
            if(pFragBot->pev->frags > fBestFrags)
            {
               iBestIndex = bot_index;
               fBestFrags = pFragBot->pev->frags;
            }
         }
      }
   }
   return iBestIndex;
}


int util::highestWeaponOfEdict(edict_t *pEdict)
{
   if (!util::isPlayer(pEdict))
      return 0;

   WeaponInfo *pSelect = g_weapons;
   int iWeapons = pEdict->v.weapons;
   int iNum = 0;
   int i = 0;

   // loop through all the weapons until terminator is found...
   while (pSelect->id)
   {
      // is the agent carrying this weapon?
      if (iWeapons & (1 << pSelect->id))
         iNum = i;
      i++;
      pSelect++;
   }

   return iNum;
}

/**
* \brief Gets the agent index into the global agents structure.
*
* \param[in] pent The agent's entity.
**/
int util::getAgentIndex(edict_t *pent)
{
   if (FNullEnt(pent))
      return -1;

   int index = ENTINDEX(pent) - 1;
   if (index < 0 || index >= 32)
      return -1;

   if (g_world->agents[index])
      return index;

   return -1;  // return -1 if edict is not an agent
}

/**
* \brief Gets the agent's team.
*
* \param[in] pEntity The agent's entity.
**/
CounterStrikeTeams::Enumeration util::getTeam(edict_t *pEntity)
{
   union
   {
      short s;
      char c[2];
   } t;

   char *p = g_engfuncs.pfnInfoKeyValue(g_engfuncs.pfnGetInfoKeyBuffer(pEntity), "model");
   t.c[0] = p[0];
   t.c[1] = p[1];

   if (t.s == (('e' << 8) + 't') || // TError
      t.s == (('e' << 8) + 'l') || // LEet
      t.s == (('r' << 8) + 'a') || // ARctic
      t.s == (('u' << 8) + 'g') || // GUerilla
      t.s == (('i' << 8) + 'm')) // MIlitia
      return CounterStrikeTeams::terrorist;

   return CounterStrikeTeams::counterTerrorist; // URban, GSg9, SAs, GIgn, VIp, SPetsnaz
}
/**
*
**/
bool util::isReachable(const Vector &v_src, const Vector &v_dest)
{
   TraceResult tr;
   float height, last_height;

   float distance = (v_dest - v_src).Length();

   // is the destination close enough?
   if (distance < 256)
   {
      bool bIsVisible = false;
      bool bIsNearDoor = false;

      // check if this waypoint is visible...
      util::traceHull(v_src, v_dest, ignore_monsters, head_hull, NULL, &tr);
      if (tr.flFraction >= 1.0)
         bIsVisible = true;

      // check if this waypoint is near a door
      util::traceline(v_src, v_dest, ignore_monsters, NULL, &tr);
      if (!FNullEnt(tr.pHit))
      {
         if (FClassnameIs(tr.pHit, "func_door") ||
            FClassnameIs(tr.pHit, "func_door_rotating"))
            bIsNearDoor = true;
      }

      // if waypoint is visible from current position (even behind head)...
      if (bIsVisible || bIsNearDoor)
      {
         if (bIsNearDoor)
         {
            // If it's a door check if nothing blocks behind
            Vector vDoorEnd = tr.vecEndPos;
            util::traceline(vDoorEnd, v_dest, ignore_monsters, ignore_glass, tr.pHit, &tr);
            if (tr.flFraction < 1.0)
               return false;
         }

         // check for special case of waypoint being suspended in mid-air...

         // is dest waypoint higher than src? (45 is max jump height)
         if (v_dest.z > v_src.z + 45.0)
         {
            Vector v_new_src = v_dest;
            Vector v_new_dest = v_dest;

            v_new_dest.z = v_new_dest.z - 50;  // straight down 50 units

            util::traceline(v_new_src, v_new_dest, ignore_monsters, ignore_glass, NULL, &tr);

            // check if we didn't hit anything, if not then it's in mid-air
            if (tr.flFraction >= 1.0)
               return false;  // can't reach this one
         }

         // check if distance to ground drops more than step height at points
         // between source and destination...

         Vector v_direction = (v_dest - v_src).Normalize();  // 1 unit long
         Vector v_check = v_src;
         Vector v_down = v_src;

         v_down.z = v_down.z - 1000.0;  // straight down 1000 units

         util::traceline(v_check, v_down, ignore_monsters, ignore_glass, NULL, &tr);

         last_height = tr.flFraction * 1000.0;  // height from ground

         distance = (v_dest - v_check).Length();  // distance from goal

         while (distance > 10.0)
         {
            // move 10 units closer to the goal...
            v_check = v_check + v_direction * 10.0;

            v_down = v_check;
            v_down.z = v_down.z - 1000.0;  // straight down 1000 units

            util::traceline(v_check, v_down, ignore_monsters, ignore_glass, NULL, &tr);

            height = tr.flFraction * 1000.0;  // height from ground

            if (height < last_height - 18.0) // is the current height greater than the step height?
               return false; // can't get there without jumping

            last_height = height;

            distance = (v_dest - v_check).Length();  // distance from goal
         }
         return true;
      }
   }
   return false;
}

/**
* \brief Whether an entity can break. 
* 
* \param[in] pent A world entity.
**/
bool util::isShootableBreakable(edict_t *pent)
{
   if (FClassnameIs(pent, "func_breakable") ||
      (FClassnameIs(pent, "func_pushable") && (pent->v.spawnflags & SF_PUSH_BREAKABLE)))
   {
      return (pent->v.takedamage != DAMAGE_NO && // can take damage
         pent->v.impulse <= 0 && // can't explode
         !(pent->v.flags & FL_WORLDBRUSH) && // not worldbrush
         !(pent->v.spawnflags & SF_BREAK_TRIGGER_ONLY) &&
         pent->v.health < 500);
   }

   return false;
}


/**
* \brief Returns the velocity at which an object should be lobbed from vecspot1 to land near vecspot2.
* 
* \return Vector zero if toss is not feasible.
**/
Vector util::vecCheckToss( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, float flGravityAdj )
{
   TraceResult    tr;
   Vector         vecMidPoint; // halfway point between Spot1 and Spot2
   Vector         vecApex; // highest point 
   Vector         vecScale;
   Vector         vecGrenadeVel;
   Vector         vecTemp;
   float          flGravity = CVAR_GET_FLOAT( "sv_gravity" ) * flGravityAdj;

   if (vecSpot2.z - vecSpot1.z > 500)
      return g_vecZero; // too high, fail

   // calculate the midpoint and apex of the 'triangle'
   // UNDONE: normalize any Z position differences between spot1 and spot2 so that triangle is always RIGHT

   // How much time does it take to get there?

   // get a rough idea of how high it can be thrown
   vecMidPoint = vecSpot1 + (vecSpot2 - vecSpot1) * 0.5;
   util::traceHull(vecMidPoint, vecMidPoint + Vector(0, 0, 500), ignore_monsters, head_hull, ENT(pev), &tr);
   vecMidPoint = tr.vecEndPos;
   // (subtract 15 so the grenade doesn't hit the ceiling)
   vecMidPoint.z -= 15;

   if (vecMidPoint.z < vecSpot1.z || vecMidPoint.z < vecSpot2.z)
      return g_vecZero; // to not enough space, fail

   // How high should the grenade travel to reach the apex
   float distance1 = vecMidPoint.z - vecSpot1.z;
   float distance2 = vecMidPoint.z - vecSpot2.z;

   // How long will it take for the grenade to travel this distance
   float time1 = sqrt( distance1 / (0.5 * flGravity) );
   float time2 = sqrt( distance2 / (0.5 * flGravity) );

   if (time1 < 0.1)
      return g_vecZero; // too close

   if (time1 + time2 > GRENADE_TIMER)
      return g_vecZero; // grenade is likely to explode in the sky

   // how hard to throw sideways to get there in time.
   vecGrenadeVel = (vecSpot2 - vecSpot1) / (time1 + time2);
   // how hard upwards to reach the apex at the right time.
   vecGrenadeVel.z = flGravity * time1;

   // find the apex
   vecApex = vecSpot1 + vecGrenadeVel * time1;
   vecApex.z = vecMidPoint.z;

   util::traceHull(vecSpot1, vecApex, dont_ignore_monsters, head_hull, ENT(pev), &tr);
   if (tr.flFraction != 1.0)
      return g_vecZero; // fail!

   // UNDONE: either ignore monsters or change it to not care if we hit our enemy
   util::traceHull(vecSpot2, vecApex, ignore_monsters, head_hull, ENT(pev), &tr); 
   if (tr.flFraction != 1.0)
   {
      Vector vecDir = (vecApex - vecSpot2).Normalize();
      float n = -DotProduct(tr.vecPlaneNormal, vecDir);
      if (n > 0.7 || tr.flFraction < 0.8) // 60 degrees
         return g_vecZero; // fail!
   }

   return vecGrenadeVel;
}

/**
* \brief Returns the velocity vector at which an object should be thrown from vecspot1 to hit vecspot2.
*
* \return Vector zero if throw is not feasible.
**/
Vector util::vecCheckThrow( 
						 entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, 
						 float flSpeed, float flGravityAdj )
{
   float flGravity = CVAR_GET_FLOAT( "sv_gravity" ) * flGravityAdj;
   Vector vecGrenadeVel = (vecSpot2 - vecSpot1);
   TraceResult tr;

   // throw at a constant time
   float time = vecGrenadeVel.Length() / flSpeed;

   if (time > GRENADE_TIMER || time < 0.1)
      return g_vecZero; // fail

   vecGrenadeVel = vecGrenadeVel / time;

   // adjust upward toss to compensate for gravity loss
   vecGrenadeVel.z += flGravity * time * 0.5;

   Vector vecApex = vecSpot1 + (vecSpot2 - vecSpot1) * 0.5;
   vecApex.z += 0.5 * flGravity * (time * 0.5) * (time * 0.5);

   util::traceHull(vecSpot1, vecApex, dont_ignore_monsters, head_hull, ENT(pev), &tr);
   if (tr.flFraction != 1.0 || tr.fAllSolid)
      return g_vecZero; // fail!

   util::traceHull(vecSpot2, vecApex, ignore_monsters, head_hull, ENT(pev), &tr);
   if (tr.flFraction != 1.0 || tr.fAllSolid)
   {
      Vector vecDir = (vecApex - vecSpot2).Normalize();
      float n = -DotProduct(tr.vecPlaneNormal, vecDir);
      if (n > 0.7 || tr.flFraction < 0.8) // 60 degrees
         return g_vecZero; // fail!
   }

   return vecGrenadeVel;
}


/**
* \brief Returns 2D travel time to a position.
**/
float util::getTravelTime(float fMaxSpeed, Vector vecSource, Vector vecPosition)
{
   float distance = (vecPosition - vecSource).Length2D();
   return (distance / fMaxSpeed);
}
/** 
* \brief Provide fakeclients (agents) with the same client command-scripting advantages 
* (putting multiple commands in one line between semicolons) as real players. 
*
* It is an improved version of botman's util::fakeClientCommand, in which you
* supply directly the whole string as if you were typing it in the agent's "console". It
* is supposed to work exactly like the pfnClientCommand (server-sided client command).
 **/
void util::fakeClientCommand(edict_t *pFakeClient, const char *fmt, ...)
{
   va_list argptr;
   static char command[256];
   int length, fieldstart, fieldstop, i, index, stringindex = 0;

   if (FNullEnt(pFakeClient))
      return; // reliability check

   // concatenate all the arguments in one string
   va_start(argptr, fmt);
   _vsnprintf(command, sizeof(command), fmt, argptr);
   va_end(argptr);

   if (util::isNullString(command))
      return; // if nothing in the command buffer, return

   g_isFakeClientCommand = true; // set the "fakeclient command" flag
   length = strlen(command); // get the total length of the command string

   // process all individual commands (separated by a semicolon) one each a time
   while (stringindex < length)
   {
      fieldstart = stringindex; // save field start position (first character)
      while (stringindex < length && command[stringindex] != ';')
         stringindex++; // reach end of field
      if (command[stringindex - 1] == '\n')
         fieldstop = stringindex - 2; // discard any trailing '\n' if needed
      else
         fieldstop = stringindex - 1; // save field stop position (last character before semicolon or end)
      for (i = fieldstart; i <= fieldstop; i++)
         g_argv[i - fieldstart] = command[i]; // store the field value in the g_argv global string
      g_argv[i - fieldstart] = 0; // terminate the string
      stringindex++; // move the overall string index one step further to bypass the semicolon

      index = 0;
      g_fakeArgCount = 0; // let's now parse that command and count the different arguments

      // count the number of arguments
      while (index < i - fieldstart)
      {
         while (index < i - fieldstart && g_argv[index] == ' ')
            index++; // ignore spaces

         // is this field a group of words between quotes or a single word ?
         if (g_argv[index] == '"')
         {
            index++; // move one step further to bypass the quote
            while (index < i - fieldstart && g_argv[index] != '"')
               index++; // reach end of field
            index++; // move one step further to bypass the quote
         }
         else
            while (index < i - fieldstart && g_argv[index] != ' ')
               index++; // this is a single word, so reach the end of field

         g_fakeArgCount++; // we have processed one argument more
      }

      // tell now the MOD DLL to execute this ClientCommand...
      MDLL_ClientCommand(pFakeClient);
   }

   g_argv[0] = 0; // when it's done, reset the g_argv field
   g_isFakeClientCommand = false; // reset the "fakeclient command" flag
   g_fakeArgCount = 0; // and the argument count
}

/**
*
**/
unsigned short util::fixedUnsigned16( float value, float scale )
{
   int output;

   output = value * scale;
   if ( output < 0 )
      output = 0;
   if ( output > 0xFFFF )
      output = 0xFFFF;

   return (unsigned short)output;
}

/**
*
**/
short util::fixedSigned16( float value, float scale )
{
   int output;

   output = value * scale;

   if ( output > 32767 )
      output = 32767;

   if ( output < -32768 )
      output = -32768;

   return (short)output;
}

// Pierre-Marie Baty - START (http://racc.agents-united.com)
/**
*
**/
const char *util::getArg(const char *command, int arg_number)
{
   // the purpose of this function is to provide fakeclients (agents) with the same Cmd_Argv
   // convenience the engine provides to real clients. This way the handling of real client
   // commands and agent client commands is exactly the same, just have a look in engine.cpp
   // for the hooking of pfnCmd_Argc, pfnCmd_Args and pfnCmd_Argv, which redirects the call
   // either to the actual engine functions (when the caller is a real client), either on
   // our function here, which does the same thing, when the caller is an agent.

   int length, i, index = 0, arg_count = 0, fieldstart, fieldstop;

   arg[0] = 0; // reset arg
   length = strlen (command); // get length of command

   // while we have not reached end of line
   while (index < length && arg_count <= arg_number)
   {
      while (index < length && command[index] == ' ')
         index++; // ignore spaces

      // is this field multi-word between quotes or single word?
      if (command[index] == '"')
      {
         index++; // move one step further to bypass the quote
         fieldstart = index; // save field start position
         while (index < length && command[index] != '"')
            index++; // reach end of field
         fieldstop = index - 1; // save field stop position
         index++; // move one step further to bypass the quote
      }
      else
      {
         fieldstart = index; // save field start position
         while (index < length && command[index] != ' ')
            index++; // reach end of field
         fieldstop = index - 1; // save field stop position
      }

      // is this argument we just processed the wanted one?
      if (arg_count == arg_number)
      {
         for (i = fieldstart; i <= fieldstop; i++)
            arg[i - fieldstart] = command[i]; // store the field value in a string
         arg[i - fieldstart] = 0; // terminate the string
      }

      arg_count++; // we have processed one argument more
   }

   return arg; // returns the wanted argument
}

/**
*
**/
char* util::varArgs( char *format, ... )
{
   va_list        argptr;
   static char    string[1024];

   va_start(argptr, format);
   _vsnprintf(string, sizeof(string), format, argptr);
   va_end(argptr);

   return string;
}


/**
* \brief Whether a string is null or the empty string.
*
* \param[in] str The string.
**/
bool util::isNullString(const char *str) {
   if (str == NULL)
      return true;
   return (*str == '\0');
}
/**
* 
**/
util::strings::StringNode *util::getNodeString(util::strings::StringNode* pNode,int NodeNum)
{
   util::strings::StringNode *pTempNode = pNode;
   int i = 0;
   while (i < NodeNum)
   {
      pTempNode = pTempNode->Next;
      assert(pTempNode);
      if (pTempNode == NULL)
         break;
      i++;
   }
   return pTempNode;
}




/**
* \brief Removes leading and trailing blanks from the messages.
**/
void util::trimBlanks(char *in_string, char *out_string)
{
   int i, pos;
   char *dest;

   pos = 0;
   while (pos < 80 && in_string[pos] == ' ')  // skip leading blanks
      pos++;

   dest = out_string;

   while (pos < 80 && in_string[pos])
   {
      *dest++ = in_string[pos];
      pos++;
   }
   *dest = 0;  // store the null

   i = strlen(out_string) - 1;
   while (i > 0 && out_string[i] == ' ')  // remove trailing blanks
   {
      out_string[i] = 0;
      i--;
   }
}

/**
* \brief Removes tags (e.g., [tag], {tag}, etc.) from messages.
**/
int util::chatTrimTag(char *original_name, char *out_name)
{
   int i;
   char *pos1, *pos2, *src, *dest;
   char in_name[80];
   int result = 0;

   strncpy(in_name, original_name, 31);
   in_name[32] = 0;

   for (i = 0; i < NUM_TAGS; i++)
   {
      pos1=strstr(in_name, g_tag1[i]);
      if (pos1)
         pos2 = strstr(pos1 + strlen(g_tag1[i]), g_tag2[i]);
      else
         pos2 = NULL;

      if (pos1 && pos2 && pos1 < pos2)
      {
         src = pos2 + strlen(g_tag2[i]);
         dest = pos1;
         while (*src)
            *dest++ = *src++;
         *dest = *src;  // copy the null;

         result = 1;
      }
   }

   strcpy(out_name, in_name);

   util::trimBlanks(out_name, in_name);

   if (strlen(in_name) == 0)  // is name just a tag?
   {
      strncpy(in_name, original_name, 31);
      in_name[32] = 0;

      // strip just the tag part...
      for (i = 0; i < NUM_TAGS; i++)
      {
         pos1 = strstr(in_name, g_tag1[i]);
         if (pos1)
            pos2 = strstr(pos1 + strlen(g_tag1[i]), g_tag2[i]);
         else
            pos2 = NULL;

         if (pos1 && pos2 && pos1 < pos2)
         {
            src = pos1 + strlen(g_tag1[i]);
            dest = pos1;
            while (*src)
               *dest++ = *src++;
            *dest = *src;  // copy the null;

            src = pos2 - strlen(g_tag2[i]);
            *src = 0; // null out the rest of the string
         }
      }
   }
   util::trimBlanks(in_name, out_name);
   out_name[31] = 0;

   return result;
}

/**
* \brief Converts given names to a more human like style for output.
**/
void util::convertNameToHuman(const char *original_name, char *out_name)
{
   strcpy(out_name, original_name);
   
   int len = strlen(out_name);
   if (out_name[len-1] == ')')
   {
      for (int pos = len - 1; pos >= len-5; pos--)
      {
         if (out_name[pos] == '(')
         {
            out_name[pos] = 0;
            break;
         }
      }
   }
}

/**
* \brief Drops a random character from a chat message. 
*
* Used to simulate human chat behaviour.
**/
void util::dropCharacter(char *out_string)
{
   int len, pos;
   int count = 0;
   char *src, *dest;

   len = strlen(out_string);
   pos = RANDOM_LONG(1, len-1);  // don't drop position zero

   while (!isalpha(out_string[pos]) && count < 20)
   {
      pos = RANDOM_LONG(1, len-1);
      count++;
   }

   if (count < 20)
   {
      src = &out_string[pos+1];
      dest = &out_string[pos];
      while (*src)
         *dest++ = *src++;
      *dest = *src;  // copy the null
   }
}


/**
* \brief Swaps a random character from a chat message.
*
* Used to simulate human chat behaviour.
**/
void util::swapCharacter(char *out_string)
{
   int len, pos;
   int count = 0;
   char temp;
   bool is_bad;

   len = strlen(out_string);
   pos = RANDOM_LONG(1, len-2);  // don't swap position zero

   is_bad = !isalpha(out_string[pos]) || !isalpha(out_string[pos+1]);

   while ((is_bad) && (count < 20))
   {
      pos = RANDOM_LONG(1, len-2);
      is_bad = !isalpha(out_string[pos]) || !isalpha(out_string[pos+1]);
      count++;
   }

   if (count < 20)
   {
      temp = out_string[pos];
      out_string[pos] = out_string[pos+1];
      out_string[pos+1] = temp;
   }
}

/**
* \brief Gets the game directory associated with a specific MOD.
*
* \param[out] mod_name The game directory.
**/
void util::getGameDirectory(char *mod_name)
{
   GET_GAME_DIR(mod_name); // ask the engine for the MOD directory path
   int length = strlen(mod_name); // get the length of the returned string

   // format the returned string to get the last directory name
   int fieldstop = length - 1;
   while ((mod_name[fieldstop] == '\\' || mod_name[fieldstop] == '/') && fieldstop > 0)
      fieldstop--; // shift back any trailing separator

   int fieldstart = fieldstop;
   while (mod_name[fieldstart] != '\\' && mod_name[fieldstart] != '/' && fieldstart > 0)
      fieldstart--; // shift back to the start of the last subdirectory name

   if (mod_name[fieldstart] == '\\' || mod_name[fieldstart] == '/')
      fieldstart++; // if we reached a separator, step over it

   // now copy the formatted string back onto itself character per character
   for (length = fieldstart; length <= fieldstop; length++)
      mod_name[length - fieldstart] = mod_name[length];
   mod_name[length - fieldstart] = 0; // terminate the string
}

/**
* \brief Gets the mod directory.
*
* \param[out] dir The mod directory.
**/
void util::getModDirectory(char *dir)
{
	util::getGameDirectory(dir);
	strcat(dir, "/addons/aasmCsAgents");
	strcat(dir, AASM_GROUP_ID);
	strcat(dir, "/");
}
/**
*  \brief Gets the mod name.
**/
void util::getModName(char* name)
{
	strcpy(name, "AASM");
	strcat(name, AASM_GROUP_ID);
}
// Pierre-Marie Baty - END

/**
*  \brief Helper function to parse in a text from File.
**/
void util::fillBufferFromFile(FILE* fpFile, char *pszBuffer, int file_index)
{
   int ch;

   ch = fgetc(fpFile);

   // skip any leading blanks
   while (ch == ' ')
      ch = fgetc(fpFile);

   while (ch != EOF && ch != '\r' && ch != '\n')
   {
      if (ch == '\t')  // convert tabs to spaces
         ch = ' ';

      pszBuffer[file_index] = ch;

      ch = fgetc(fpFile);

      // skip multiple spaces in input file
      while (pszBuffer[file_index] == ' ' && ch == ' ')
         ch = fgetc(fpFile);

      file_index++;
   }

   while (ch == '\r')  // is it a carriage return?
      ch = fgetc(fpFile);  // skip the linefeed

   pszBuffer[file_index] = 0;  // terminate the command line
}

/**
*  \brief Create a directory tree.
**/
void util::createPath(char *path)
{
   char *ofs;

   for (ofs = path + 1 ; *ofs ; ofs++)
   {
      if (*ofs == '/')
      {
         // create the directory
         *ofs = 0;
#ifdef _WIN32
         mkdir(path);
#else
         mkdir(path, 0777);
#endif
         *ofs = '/';
      }
   }
#ifdef _WIN32
   mkdir(path);
#else
   mkdir(path, 0777);
#endif
}


/**
*
**/
void util::showMenu( edict_t *pEdict, int slots, int displaytime, bool needmore, const char *pText )
{
   if (gmsgShowMenu == 0)
      gmsgShowMenu = REG_USER_MSG( "ShowMenu", -1 );

   while (strlen(pText) >= 64)
   {
      MESSAGE_BEGIN(MSG_ONE, gmsgShowMenu, NULL, pEdict);
         WRITE_SHORT(slots);
         WRITE_CHAR(displaytime);
         WRITE_BYTE(1);
         for (int i = 0; i <= 63; i++)
            WRITE_CHAR(pText[i]);
      MESSAGE_END();

      pText += 64;
   }

   MESSAGE_BEGIN(MSG_ONE, gmsgShowMenu, NULL, pEdict);
      WRITE_SHORT(slots);
      WRITE_CHAR(displaytime);
      WRITE_BYTE(needmore);
      WRITE_STRING(pText);
   MESSAGE_END();
}

/**
*  \brief Prints a text message on the screen.
**/
void util::hostPrint(edict_t *pEntity, PRINT_TYPE msg_dest, const char *fmt, ...)
{
   va_list va_alist;
   char msg[256];

   va_start(va_alist, fmt);
   _vsnprintf(msg, sizeof(msg), fmt, va_alist);
   va_end(va_alist);

   if (!util::isPlayer(pEntity))
      SERVER_PRINT(msg);
   else
      g_engfuncs.pfnClientPrintf(pEntity, msg_dest, msg);
}

/**
*
**/
void ClientPrint( 
				 entvars_t *client, int msg_dest, const char *msg_name, 
				 const char *param1, const char *param2, const char *param3, 
				 const char *param4 )
{
   if (FNullEnt(client))
      return; // reliability check

   if (gmsgTextMsg == 0)
      gmsgTextMsg = REG_USER_MSG( "TextMsg", -1 );

   MESSAGE_BEGIN( MSG_ONE, gmsgTextMsg, NULL, client );

   WRITE_BYTE( msg_dest );
   WRITE_STRING( msg_name );
   if ( param1 )
      WRITE_STRING( param1 );
   if ( param2 )
      WRITE_STRING( param2 );
   if ( param3 )
      WRITE_STRING( param3 );
   if ( param4 )
      WRITE_STRING( param4 );
   MESSAGE_END();
}

/**
*
**/
void util::clientPrintAll( 
						int msg_dest, const char *msg_name, const char *param1, 
						const char *param2, const char *param3, const char *param4 )
{
   if (gmsgTextMsg == 0)
      gmsgTextMsg = REG_USER_MSG( "TextMsg", -1 );

   MESSAGE_BEGIN( MSG_ALL, gmsgTextMsg );
      WRITE_BYTE( msg_dest );
      WRITE_STRING( msg_name );
      if ( param1 )
         WRITE_STRING( param1 );
      if ( param2 )
         WRITE_STRING( param2 );
      if ( param3 )
         WRITE_STRING( param3 );
      if ( param4 )
         WRITE_STRING( param4 );
   MESSAGE_END();
}



/**
*  \brief Terminate the application with an error.
*
* \param[in] string The error message.
**/
void util::terminateOnError(const char *string)
{
   util::freeAllTheStuff();
   ALERT(at_error, "%s\n", string);
#ifdef _WIN32
   MessageBox(0, string, "FATAL ERROR", MB_ICONERROR);
#endif
   exit(1);
}

/**
*  \brief Free all allocated memory.
**/
void util::freeAllTheStuff(void)
{
   for (int i = 0; i < 32; i++)
   {
      if (g_world->agents[i])
         delete g_world->agents[i];
   }

   game::waypoints::reset(); // Frees waypoint data

   if (g_terroristWaypoints)
      free(g_terroristWaypoints);
   g_terroristWaypoints = NULL;

   if (g_counterTerroristWaypoints)
      free(g_counterTerroristWaypoints);
   g_counterTerroristWaypoints = NULL;

   if (g_goalWaypoints)
      free(g_goalWaypoints);
   g_goalWaypoints = NULL;

   if (g_campWaypoints)
      free(g_campWaypoints);
   g_campWaypoints = NULL;

   if (g_rescueWaypoints)
      free(g_rescueWaypoints);
   g_rescueWaypoints = NULL;

   if (game::search::g_pFloydDistanceMatrix)
   {
      free(game::search::g_pFloydDistanceMatrix);
      game::search::g_pFloydDistanceMatrix = NULL;
   }

   if (game::search::g_pFloydPathMatrix)
   {
      free(game::search::g_pFloydPathMatrix);
      game::search::g_pFloydPathMatrix = NULL;
   }
}
/**
*  \brief Finds an entity from its position.
* 
* \param[in] The position.
**/
edict_t* util::findEntityBasedOnOrigin(Vector origin)
{
	for(int i=0; i<gpGlobals->maxClients; i++)
	{
		if(!g_threatTab[i].isUsed)
			continue;

		if(util::math::compareVectors(g_threatTab[i].origin, origin, 0))
			return g_threatTab[i].pEdict;
	}

	return NULL;
}